home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / viewkit / VCal / TimeEntry.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  15.4 KB  |  677 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include <stdio.h>
  18. #include <malloc.h>
  19. #include "TimeEntry.h"
  20. #include "TimeGrid.h"
  21. #include "TimeInterval.h"
  22.  
  23. #include <Xm/Frame.h>
  24. #include <Xm/LabelG.h>
  25. #include <Xm/Text.h>
  26.  
  27. static int count;
  28. static Arg args[10];
  29. static Boolean deleted;
  30. static TimeEntry *deletedObject;
  31.  
  32. char *
  33. xs_get_string_from_xmstring (XmString string)
  34. {
  35.   XmStringContext   context;
  36.   char             *text;
  37.   XmStringCharSet   charset;
  38.   XmStringDirection dir;
  39.   Boolean           separator;
  40.   char             *buf = NULL;
  41.  
  42.   int               done = FALSE;
  43.   XmStringInitContext (&context, string);
  44.   while (!done)
  45.     if(XmStringGetNextSegment (context, &text, &charset,
  46.                    &dir, &separator)){
  47.       if(buf){
  48.     buf = XtRealloc(buf, strlen(buf) + strlen(text) + 2);
  49.     strcat(buf, text);
  50.       }
  51.       else {
  52.     buf = (char *) XtMalloc(strlen(text) +1);
  53.     strcpy(buf, text);
  54.       }
  55.       XtFree(text);
  56.       if(buf && separator) {
  57.     buf = XtRealloc(buf, strlen(buf) + 2);
  58.     strcat(buf, "\n");
  59.       }
  60.     }
  61.     else
  62.       done = TRUE;
  63.  
  64.   XmStringFreeContext (context);
  65.   if (buf && buf[strlen(buf)-1] == '\n') {
  66.     buf[strlen(buf)-1] = '\0';
  67.   }
  68.   return buf;
  69. }
  70.  
  71.  
  72. TimeEntry::TimeEntry(const char *n, TimeGrid *grid)
  73. : VkComponent(n)
  74. {
  75.   _grid = grid;
  76.  
  77.   _callback = NULL;
  78.  
  79.   TimeEntry::build();
  80. }
  81.  
  82. TimeEntry::~TimeEntry()
  83. {
  84.   if (::deletedObject == this) {
  85.     ::deleted = True;
  86.   }
  87.   if (_baseWidget) {
  88.     XtRemoveEventHandler(_baseWidget, ButtonPressMask, False,
  89.              TimeEntry::button_press, (XtPointer) this);
  90.   }
  91.   if (_grid->getText() &&
  92.       _grid->getText()->getCallbackData() == (XtPointer) this) {
  93.     _grid->getText()->setCallback(NULL, NULL);
  94.     _grid->getText()->hide();
  95.   }
  96. }
  97.  
  98. /**********************************************************************/
  99.  
  100. const char *
  101. TimeEntry::className()
  102. {
  103.   return "TimeEntry";
  104. }
  105.  
  106. void
  107. TimeEntry::raise()
  108. {
  109.   if (XtWindow(_baseWidget)) {
  110.     XRaiseWindow(XtDisplay(_baseWidget), XtWindow(_baseWidget));
  111.   }
  112. }
  113.  
  114. void
  115. TimeEntry::setCallback(XtCallbackProc proc, XtPointer client_data)
  116. {
  117.   _callback = proc;
  118.   _callbackData = client_data;
  119. }
  120.  
  121. Boolean
  122. TimeEntry::setTimeInterval(int s, int l)
  123. {
  124.   _start = s;
  125.   _length = l;
  126.   if (_baseWidget) {
  127.     return reposition();
  128.   } else {
  129.     return True;
  130.   }
  131. }
  132.  
  133. char *
  134. TimeEntry::getText()
  135. {
  136.   XmString xs;
  137.   char *result;
  138.  
  139.   count = 0;
  140.   XtSetArg(args[count], XmNlabelString, &xs);  count++;
  141.   XtGetValues(_label, args, count);
  142.   if (result = xs_get_string_from_xmstring(xs)) {
  143.     return result;
  144.   } else {
  145.     return strdup("");
  146.   }
  147. /*
  148.   if (XmStringGetLtoR(xs, XmSTRING_DEFAULT_CHARSET, &result)) {
  149.     return result;
  150.   } else {
  151.     return strdup("");
  152.   }
  153. */
  154. }
  155.  
  156. void
  157. TimeEntry::setText(char *str)
  158. {
  159.   XmString xs;
  160.  
  161.   xs = XmStringCreateLtoR(str, XmFONTLIST_DEFAULT_TAG);
  162.   count = 0;
  163.   XtSetArg(args[count], XmNlabelString, xs);  count++;
  164.   XtSetValues(_label, args, count);
  165.   XmStringFree(xs);
  166. }
  167.  
  168. Boolean
  169. TimeEntry::reposition()
  170. {
  171.   Position x, y;
  172.   Dimension width, height;
  173.  
  174.   if (_grid->requestPosition(_start, _length, &x, &y, &width, &height)) {
  175.     count = 0;
  176.     XtSetArg(args[count], XmNx, x);  count++;
  177.     XtSetArg(args[count], XmNy, y);  count++;
  178.     XtSetArg(args[count], XmNwidth, width);  count++;
  179.     XtSetArg(args[count], XmNheight, height);  count++;
  180.     XtSetValues(_baseWidget, args, count);
  181.     return True;
  182.   } else {
  183.     return False;
  184.   }
  185. }
  186.  
  187. void
  188. TimeEntry::callCallback(TimeEntryReason reason, XEvent *event)
  189. {
  190.   TimeEntryCallback data;
  191.  
  192.   if (_callback) {
  193.     data.obj = this;
  194.     data.reason = reason;
  195.     data.event = event;
  196.     (*_callback)(_baseWidget, _callbackData, (XtPointer) &data);
  197.   }
  198. }
  199.  
  200. void
  201. TimeEntry::select(Boolean makeModified)
  202. {
  203.   raise();
  204.   callCallback(TE_selected);
  205.   layerText(makeModified);
  206. }
  207.  
  208. /**********************************************************************/
  209.  
  210. void
  211. TimeEntry::build()
  212. {
  213.   Pixel topShadow, bottomShadow, bg, fg;
  214.   Dimension shadowThickness;
  215.  
  216.   if (_grid->getText()) {
  217.     count = 0;
  218.     XtSetArg(args[count], XmNbackground, &bg);  count++;
  219.     XtSetArg(args[count], XmNforeground, &fg);  count++;
  220.     XtSetArg(args[count], XmNtopShadowColor, &topShadow);  count++;
  221.     XtSetArg(args[count], XmNbottomShadowColor, &bottomShadow);  count++;
  222.     XtSetArg(args[count], XmNshadowThickness, &shadowThickness);  count++;
  223.     XtGetValues(_grid->getText()->baseWidget(), args, count);
  224.   }
  225.  
  226.   count = 0;
  227.   XtSetArg(args[count], XmNshadowType, XmSHADOW_ETCHED_IN);
  228.   XtSetArg(args[count], XmNhighlightThickness, 0);  count++;
  229.   if (_grid->getText()) {
  230.     XtSetArg(args[count], XmNbackground, bg);  count++;
  231.     XtSetArg(args[count], XmNforeground, fg);  count++;
  232.     XtSetArg(args[count], XmNtopShadowColor, topShadow);  count++;
  233.     XtSetArg(args[count], XmNbottomShadowColor, bottomShadow);  count++;
  234.     XtSetArg(args[count], XmNshadowThickness, shadowThickness);  count++;
  235.   }
  236.   _baseWidget = XmCreateFrame(_grid->getParent(), _name, args, count);
  237.  
  238.   count = 0;
  239.   XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  240.   XtSetArg(args[count], XmNalignment, XmALIGNMENT_BEGINNING);  count++;
  241.   XtSetArg(args[count], XmNfontList, _grid->getTextFontList());  count++;
  242.   _label = XmCreateLabelGadget(_baseWidget, "timeEntryLabel", args, count);
  243.   XtManageChild(_label);
  244.  
  245.   XtAddEventHandler(_baseWidget, ButtonPressMask, False,
  246.             TimeEntry::button_press, (XtPointer) this);
  247.   installDestroyHandler();
  248. }
  249.  
  250. void
  251. TimeEntry::destroy()
  252. {
  253.   XtRemoveEventHandler(_baseWidget, ButtonPressMask, False,
  254.                TimeEntry::button_press, (XtPointer) this);
  255.   XtDestroyWidget(_baseWidget);  
  256. }
  257.  
  258. void
  259. TimeEntry::menu(XEvent *event)
  260. {
  261.   callCallback(TE_postMenu, event);
  262. }
  263.  
  264. void
  265. TimeEntry::layerText(Boolean makeModified)
  266. {
  267.   char *str;
  268.  
  269.  
  270. // There is the possibility that we will be deleted by resetting of the
  271. // grid, if we're the entry for the grid text entry and we don't have
  272. // a string.  I should really be able to figure out how to detect the
  273. // situation before calling TimeGrid::reset and behave differently,
  274. // but I can't do it right now.
  275.   ::deletedObject = this;
  276.   ::deleted = False;
  277.   _grid->reset();
  278.   if (::deleted) {
  279.     return;
  280.   }
  281.  
  282.   str = getText();
  283.   _grid->getText()->setText(str);
  284.   XtFree(str);
  285.   if (_grid->getText()->setTimeInterval(_start, _length)) {
  286.     _grid->getText()->show();
  287.     _grid->getText()->raise();
  288.   }
  289.   _grid->getText()->setCallback(TimeEntry::text_stub, (XtPointer) this);
  290.   _grid->getText()->setModified(makeModified);
  291. }
  292.  
  293. /**********************************************************************/
  294.  
  295. void
  296. TimeEntry::button_press(Widget, XtPointer client_data, XEvent *event,
  297.             Boolean *)
  298. {
  299.   TimeEntry *obj = (TimeEntry *) client_data;
  300.  
  301.   if (event->xbutton.button == Button1) {
  302.     obj->select();
  303.   } else if (event->xbutton.button == Button3) {
  304.     obj->menu(event);
  305.   }
  306. }
  307.  
  308. void
  309. TimeEntry::text_stub(Widget, XtPointer client_data, XtPointer call_data)
  310. {
  311.   TimeEntry *obj = (TimeEntry *) client_data;
  312.   TimeEntryCallback *cb = (TimeEntryCallback *) call_data;
  313.   char *str;
  314.  
  315.   switch (cb->reason) {
  316.   case TE_textChanged:
  317.     str = obj->_grid->getText()->getText();
  318.     obj->setText(str);
  319.     XtFree(str);
  320.     break;
  321.   case TE_timeChanged:
  322.     obj->setTimeInterval(obj->_grid->getText()->start(),
  323.              obj->_grid->getText()->length());
  324.     break;
  325.   case TE_postMenu:
  326.   case TE_selected:
  327.   case TE_deselect:
  328.   case TE_none:
  329.     break;
  330.   }
  331.   obj->callCallback(cb->reason, cb->event);
  332. }
  333.  
  334. /**********************************************************************/
  335.  
  336. TimeEntryText::TimeEntryText(const char *name, TimeGrid *grid,
  337.                  Boolean editable)
  338. : TimeEntry(name, grid)
  339. {
  340.   _modified = False;
  341.   _nonEmpty = False;
  342.   _id = NULL;
  343.  
  344.   if (editable) {
  345.     _resizer = new VkResizer();
  346.     _resizer->addCallback(VkResizer::stateChangedCallback, this,
  347.               (VkCallbackMethod) &TimeEntryText::resizeCallback,
  348.               (XtPointer) this);
  349.   } else {
  350.     _resizer = NULL;
  351.   }
  352.  
  353.   TimeEntry::destroy();
  354.   TimeEntryText::build();
  355. }
  356.  
  357. TimeEntryText::~TimeEntryText()
  358. {
  359.   if (_baseWidget) {
  360.     XtRemoveCallback(_baseWidget, XmNactivateCallback,
  361.              TimeEntryText::activate_stub, (XtPointer) this);
  362.     XtRemoveCallback(_baseWidget, XmNmodifyVerifyCallback,
  363.              TimeEntryText::modify_stub, (XtPointer) this);
  364.     XtRemoveCallback(_baseWidget, XmNlosingFocusCallback,
  365.              TimeEntryText::focus_stub, (XtPointer) this);
  366.     XtRemoveCallback(_baseWidget, XmNvalueChangedCallback,
  367.              TimeEntryText::modified_stub, (XtPointer) this);
  368.     XtRemoveEventHandler(_baseWidget, ButtonPressMask, False,
  369.              TimeEntryText::button_press, (XtPointer) this);
  370.   }
  371.   if (_resizer) {
  372.     delete _resizer;
  373.   }
  374.   delete _interval;
  375. }
  376.  
  377. /**********************************************************************/
  378.  
  379. void
  380. TimeEntryText::hide()
  381. {
  382.   TimeEntry::hide();
  383.   if (_resizer) {
  384.     _resizer->hide();
  385.   }
  386.   _interval->hide();
  387.   textChanged();
  388. }
  389.  
  390. void
  391. TimeEntryText::raise()
  392. {
  393.   TimeEntry::raise();
  394.   if (_resizer) {
  395.     _resizer->show();
  396.   }
  397.   _interval->show();
  398.   XmProcessTraversal(_baseWidget, XmTRAVERSE_CURRENT);
  399. }
  400.  
  401. /**********************************************************************/
  402.  
  403. char *
  404. TimeEntryText::getText()
  405. {
  406.   char *str;
  407.   int len;
  408.  
  409.   str = XmTextGetString(_baseWidget);
  410.   len = strlen(str);
  411.   if (len == 1 && str[0] == '\n') {
  412.     str[0] = '\0';
  413.   } else if (len > 1 && str[len-1] == '\n' && str[len-2] == '\n') {
  414.     str[len-2] = '\0';
  415.   }
  416.   return str;
  417. }
  418.  
  419. void
  420. TimeEntryText::setText(char *str)
  421. {
  422.   XmTextSetString(_baseWidget, str);
  423.   _modified = False;
  424.   _nonEmpty = (strlen(str) != 0);
  425. }
  426.  
  427. Boolean
  428. TimeEntryText::reposition()
  429. {
  430.   Boolean result;
  431.  
  432.   result = TimeEntry::reposition();
  433.   if (result && _resizer) {
  434.     _resizer->setIncrements(0, _grid->getSlotHeight(),
  435.                 0, _grid->getSlotHeight());
  436.     _resizer->adjustGeometry();
  437.   }
  438.   return result;
  439. }
  440.  
  441. Boolean
  442. TimeEntryText::setTimeInterval(int start, int length)
  443. {
  444.   Boolean result;
  445.  
  446.   result = TimeEntry::setTimeInterval(start, length);
  447.   _interval->setTimeInterval(start, length);
  448.   return result;
  449. }
  450.  
  451. /**********************************************************************/
  452.  
  453. void
  454. TimeEntryText::build()
  455. {
  456.   count = 0;
  457.   XtSetArg(args[count], XmNhighlightThickness, 0);  count++;
  458.   _baseWidget = XmCreateText(_grid->getParent(), _name, args, count);
  459.   XtAddCallback(_baseWidget, XmNactivateCallback,
  460.         TimeEntryText::activate_stub, (XtPointer) this);
  461.   XtAddCallback(_baseWidget, XmNmodifyVerifyCallback,
  462.         TimeEntryText::modify_stub, (XtPointer) this);
  463.   XtAddCallback(_baseWidget, XmNlosingFocusCallback,
  464.         TimeEntryText::focus_stub, (XtPointer) this);
  465.   XtAddCallback(_baseWidget, XmNvalueChangedCallback,
  466.         TimeEntryText::modified_stub, (XtPointer) this);
  467.   XtAddEventHandler(_baseWidget, ButtonPressMask, False,
  468.             TimeEntryText::button_press, (XtPointer) this);
  469.   if (_resizer) {
  470.     _resizer->attach(_baseWidget);
  471.     _resizer->show();
  472.   }
  473.  
  474.   _interval = new TimeInterval("timeInterval", _grid);
  475.   _interval->setCallback(TimeEntryText::interval_stub, (XtPointer) this);
  476. }
  477.  
  478. void
  479. TimeEntryText::destroy()
  480. {
  481.   XtRemoveEventHandler(_baseWidget, ButtonPressMask, False,
  482.                TimeEntryText::button_press, (XtPointer) this);
  483.   XtDestroyWidget(_baseWidget);
  484. }
  485.  
  486. void
  487. TimeEntryText::resizeCallback(VkComponent *, XtPointer, XtPointer callData)
  488. {
  489.     VkResizerReason reason = (VkResizerReason) callData;
  490.  
  491.     switch (reason) {
  492.     case VR_resized:
  493.     case VR_moved:
  494.     updateInterval();
  495.     break;
  496.     case VR_resizing:
  497.     case VR_moving:
  498.     adjustInterval();
  499.     break;
  500.     case VR_none:
  501.     break;
  502.     }
  503. }
  504.  
  505. void
  506. TimeEntryText::updateInterval()
  507. {
  508.   int oldStart, oldLength;
  509.   Position y;
  510.   Dimension height;
  511.  
  512.   oldStart = _start;
  513.   oldLength = _length;
  514.   count = 0;
  515.   XtSetArg(args[count], XmNy, &y);  count++;
  516.   XtSetArg(args[count], XmNheight, &height);  count++;
  517.   XtGetValues(_baseWidget, args, count);
  518.   _grid->requestInterval(y, height, &_start, &_length);
  519.   _interval->setTimeInterval(_start, _length);
  520.   if (_start != oldStart || _length != oldLength) {
  521.     callCallback(TE_timeChanged);
  522.   }
  523. }
  524.  
  525. void
  526. TimeEntryText::textChanged()
  527. {
  528.   if (_modified) {
  529.     callCallback(TE_textChanged);
  530.   }
  531.   _modified = False;
  532. }
  533.  
  534. Boolean
  535. TimeEntryText::textComplete()
  536. {
  537.   char *str;
  538.   XmTextPosition insert, last;
  539.   Boolean result;
  540.   int len;
  541.  
  542.   result = False;
  543.   insert = XmTextGetInsertionPosition(_baseWidget);
  544.   last = XmTextGetLastPosition(_baseWidget);
  545.   if (insert >= last-1) {
  546.     str = XmTextGetString(_baseWidget);
  547.     len = strlen(str);
  548.     if ((len == 1 && str[0] == '\n') ||
  549.     (len > 1 && str[len-1] == '\n' && str[len-2] == '\n')) {
  550.       result = True;
  551.     }
  552.     XtFree(str);
  553.   }
  554.   return result;
  555. }
  556.  
  557. void
  558. TimeEntryText::doActivate()
  559. {
  560.   _id = NULL;
  561.   if (textComplete()) {
  562.     textChanged();
  563.     hide();
  564.     callCallback(TE_deselect);
  565.   }
  566. }
  567.  
  568. void
  569. TimeEntryText::scheduleActivate()
  570. {
  571.   if (!_id) {
  572.     _id = XtAppAddWorkProc(XtWidgetToApplicationContext(_baseWidget),
  573.                TimeEntryText::sched_activate,
  574.                (XtPointer) this);
  575.   }
  576. }
  577.  
  578. void
  579. TimeEntryText::adjustInterval()
  580. {
  581.   Position x, y;
  582.   Dimension width, height;
  583.   int start, length;
  584.  
  585.   if (_resizer) {
  586.     _resizer->lastLocation(&x, &y, &width, &height);
  587.   }
  588.   _grid->requestInterval(y, height, &start, &length);
  589.   _interval->setTimeInterval(start, length);
  590. }
  591.  
  592. /**********************************************************************/
  593.  
  594. /*
  595. void
  596. TimeEntryText::resize_stub(Widget, XtPointer client_data, XtPointer call_data)
  597. {
  598.   TimeEntryText *obj = (TimeEntryText *) client_data;
  599.   VkResizerReason reason = (VkResizerReason) call_data;
  600.  
  601.   obj->resizeCallback(reason);
  602. }
  603. */
  604.  
  605. void
  606. TimeEntryText::activate_stub(Widget, XtPointer client_data, XtPointer)
  607. {
  608.   TimeEntryText *obj = (TimeEntryText *) client_data;
  609.  
  610.   obj->scheduleActivate();
  611. }
  612.  
  613. void
  614. TimeEntryText::modify_stub(Widget, XtPointer client_data, XtPointer call_data)
  615. {
  616.   TimeEntryText *obj = (TimeEntryText *) client_data;
  617.   XmTextVerifyCallbackStruct *cb = (XmTextVerifyCallbackStruct *) call_data;
  618.  
  619.   if (cb->text->length == 1 && *(cb->text->ptr) == '\n') {
  620.     obj->scheduleActivate();
  621.   }
  622. }
  623.  
  624. void
  625. TimeEntryText::focus_stub(Widget, XtPointer client_data, XtPointer)
  626. {
  627.   TimeEntryText *obj = (TimeEntryText *) client_data;
  628.  
  629.   if (obj->_nonEmpty) {
  630.     obj->textChanged();
  631.   }
  632. }
  633.  
  634. void
  635. TimeEntryText::modified_stub(Widget, XtPointer client_data, XtPointer)
  636. {
  637.   TimeEntryText *obj = (TimeEntryText *) client_data;
  638.   char *str;
  639.  
  640.   obj->_modified = True;
  641.   str = obj->getText();
  642.   obj->_nonEmpty = (strlen(str) != 0);
  643.   XtFree(str);
  644. }
  645.  
  646. void
  647. TimeEntryText::button_press(Widget, XtPointer client_data, XEvent *event,
  648.                 Boolean *)
  649. {
  650.   TimeEntryText *obj = (TimeEntryText *) client_data;
  651.  
  652.   if (event->xbutton.button == Button3) {
  653.     obj->menu(event);
  654.   }
  655. }
  656.  
  657. Boolean
  658. TimeEntryText::sched_activate(XtPointer client_data)
  659. {
  660.   TimeEntryText *obj = (TimeEntryText *) client_data;
  661.  
  662.   obj->doActivate();
  663.   return True;
  664. }
  665.  
  666. void
  667. TimeEntryText::interval_stub(Widget, XtPointer client_data,
  668.                  XtPointer call_data)
  669. {
  670.   TimeEntryText *obj = (TimeEntryText *) client_data;
  671.   TimeIntervalReason reason = (TimeIntervalReason) call_data;
  672.  
  673.   if (reason == TI_deselect) {
  674.     obj->callCallback(TE_deselect);
  675.   }
  676. }
  677.